#ifndef _DSWRECODER_H
#define _DSWRECODER_H
#include <libbase/dswmemlistbase.h>
#include <libdswmemory/dswmemory.h>
#include <libdsw3gp/dsw3gp.h>

class CDswrecoder;

typedef struct{
	CDswrecoder* pCaller;
	int nCh;
	bool bLocal;
} ST_REC_PARAM_T, *LPST_REC_PARAM_T;

typedef struct{
	pthread_t nThreadID;
	char* pRecBuffer;
	char* pRecBufPos;
	char sRecTmpFile[256];
	time_t nStartTm;
	ST_REC_PARAM_T nRecParam;
	bool bRecodering;
} ST_RECODER_INFO_T, *LPST_RECODER_INFO_T;

typedef struct{
	pthread_mutex_t nLock;
	std::list<LPST_RECODER_INFO_T> nList;
} ST_TMP2MP4_T, *LPST_TMP2MP4_T;

typedef struct{
	CDsw3gp* p3GP;
	int nCurTotalFrames;
	ST_ALARM_NODE_T nAlarmNode;
} ST_ALARM_REC_NODE_T, *LPST_ALARM_REC_NODE_T;

typedef std::list<LPST_ALARM_REC_NODE_T> LIST_ALARM_REC_NODE_T, *LPLIST_ALARM_REC_NODE_T;

typedef struct{
	pthread_t nThreadID;
	CDswmemory* pMemory;
	LPST_LIST_MEM_T pPreRecFrameList;
	LPST_LIST_MEM_T pPreRecFrameList_UnUsed;
	pthread_mutex_t nLock;
	bool bNewParam;
	int nMaxFrames;
	int nCurFrames;
	int nTotalFrames;
	ST_REC_PARAM_T nRecParam;

	pthread_mutex_t nAlarmNodeLock;
	LIST_ALARM_REC_NODE_T nAlarmNodeList;
} ST_PRE_REC_T, *LPST_PRE_REC_T;

typedef struct{
	unsigned char* pPps;
	int* pPpsLen;
	unsigned char* pSps;
	int* pSpsLen;
	char* pBuffer;
	int nFps;
} ST_ALARM_REC_SPS_PPS_T, *LPST_ALARM_REC_SPS_PPS_T;

typedef struct{
	bool bLocal;
	ST_BS_PARAM nLocalBs;
	int nFps;
	int nWidth;
	int nHeight;
} ST_BS_PARAM_EX, *LPST_BS_PARAM_EX;

class CDswrecoder : public CDswmemlistbase
{
public:
	CDswrecoder(LPST_ENV_T pEnv);
	virtual ~CDswrecoder();
protected:
	virtual int OnMessage(EN_MSG_TYPE nMsgType, void * pParam);
private:
	void MakeSpsPps(unsigned char* pVFrame, int nLen, unsigned char* pSps, int &nSpsLen, unsigned char* pPps, int &nPpsLen){
		int nsps_len, npps_len;
		unsigned char *p_sps, *p_pps;

		p_sps = seekTosps(pVFrame, nLen, nsps_len);
		if (p_sps == NULL){
			nsps_len = -1;
			LOG4CPLUS_ERROR(log_dsw, "seekTosps error!");
			return;
		}
		p_pps = seekTopps(p_sps + nsps_len, nLen - nsps_len, npps_len);
		if (p_pps == NULL){
			npps_len = -1;
			LOG4CPLUS_ERROR(log_dsw, "seekTopps error!");
			return;
		}
		nSpsLen = nsps_len;
		memcpy(pSps, p_sps, nsps_len);
		nPpsLen = npps_len;
		memcpy(pPps, p_pps, npps_len);
	};
	unsigned char* seekTosps(unsigned char * pFrame, int nframelen, int & nspslen){
		int nTotalLen = nframelen;
		unsigned char* pPos = pFrame;
		int i = 4;
		while (i < (nTotalLen - 4)){
			if ((memcmp(pPos, "\x00\x00\x00\x01", 4) == 0) && (memcmp(&pPos[i], "\x00\x00\x00\x01", 4) != 0)){
				i++;
				continue;
			}
			if ((pPos[4] & 0x1f) == 0x07){
				nspslen = i;
				return pPos;
			}
			pPos += i;
			i = 4;
		}
		return NULL;
	};
	unsigned char* seekTopps(unsigned char * pFrame, int nframelen, int & nppslen){
		int nTotalLen = nframelen;
		unsigned char* pPos = pFrame;
		int i = 4;
		while (i < (nTotalLen - 4)){
			if ((memcmp(pPos, "\x00\x00\x00\x01", 4) == 0) && (memcmp(&pPos[i], "\x00\x00\x00\x01", 4) != 0)){
				i++;
				continue;
			}
			if ((pPos[4] & 0x1f) == 0x08){
				nppslen = i;
				return pPos;
			}
			pPos += i;
			i = 4;
		}
		return NULL;
	};
private:
	static void* cbRecThreadFunc(void* pParam){
		LPST_REC_PARAM_T pRecParam = (LPST_REC_PARAM_T)pParam;
		pRecParam->pCaller->RecThreadFunc(pRecParam->bLocal, pRecParam->nCh);
		return NULL;
	};
	void RecThreadFunc(bool bLocal, int nCh);
	void PutTmpFileToCvtList(LPST_RECODER_INFO_T pRecInfo);
	bool PutRamToTmpFile(int &nRamSize, LPST_RECODER_INFO_T pRecInfo, LPST_BS_PARAM_EX pBsParam,
		unsigned char* pSps, int nSpsLen, unsigned char* pPps, int nPpsLen);
	bool PutFrameToRam(LPST_RECODER_INFO_T pRecInfo, LPST_VIDEO_FRAME_T pFrame, int &nRamSize);

	static void* cbCvt23GPThreadFunc(void* pParam){((CDswrecoder*)pParam)->Cvt23GPThreadFunc();return NULL;};
	void Cvt23GPThreadFunc();
	void SaveTmpFileTo3gp(LPST_RECODER_INFO_T pTmpFileInfo, char* pSaveFrameBuffer);

	static void* cbAlarmRecThreadFunc(void* pParam){
		LPST_PRE_REC_T pPreRecParam = (LPST_PRE_REC_T)pParam;
		pPreRecParam->nRecParam.pCaller->AlarmRecThreadFunc(pPreRecParam);
		return NULL;
	};
	void AlarmRecThreadFunc(LPST_PRE_REC_T pPreRecParam);
	void PutFrameToPreRecRam(LPST_VIDEO_FRAME_T pFrame, LPST_PRE_REC_T pPreRecParam);
	void SetNewPreRecParam(LPST_ALARM_T pAlarmParam, LPST_VIDEO_PARAM pVParam);
	void ResetPreRec(LPST_PRE_REC_T pPreRecParam);
	void SetAlarmRecNode(LPST_ALARM_NODE_T pAlarmNode);
	void ProcessRecNodeList(LPST_VIDEO_FRAME_T pFrame, LPST_PRE_REC_T pPreRecParam, LPST_ALARM_REC_SPS_PPS_T pRecSpsPps);
	bool DumpFrame(void* pSrc, void* pDest, CDswmemory* pMemory);
private:
	pthread_t m_nThread_cvt;
	ST_RECODER_INFO_T m_nRecLocal[MAX_CHANNEL_LOCAL], m_nRecRemote[MAX_CHANNEL_REMOTE];
	ST_TMP2MP4_T m_nTmp2MP4;
	ST_PRE_REC_T m_nPreRec_L[MAX_CHANNEL_LOCAL], m_nPreRec_R[MAX_CHANNEL_REMOTE];

	pthread_mutex_t m_nAlarmNodeLock;
	LIST_ALARM_REC_NODE_T m_nAlarmNodeList;

	bool m_bConverting;

//	pthread_mutex_t m_nTestLock;
};

#endif

